package net.qiqbframework.modelling.repository;

import lombok.extern.slf4j.Slf4j;
import net.qiqbframework.loadhanding.AggregateLoadBus;
import net.qiqbframework.loadhanding.GenericLoadMessage;
import net.qiqbframework.loadhanding.JdbcAggregate;
import net.qiqbframework.loadhanding.LoadMessage;
import net.qiqbframework.modelling.domain.AggregateModel;
import net.qiqbframework.modelling.domain.AggregateNotFoundException;
import net.qiqbframework.persisthanding.AggregatePersistBus;
import net.qiqbframework.persisthanding.GenericPersistMessage;
import net.qiqbframework.serialization.Serializer;

import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;

import static net.qiqbframework.common.BuilderUtils.assertNonNull;

/**
 * 通过 hanlder 来获取或者聚合对象
 *
 * @param <T>
 */
@Slf4j
public class HandlerRepository<T> extends AbstractRepository<T, JdbcAggregate<T>> {


    protected final AggregateLoadBus aggregateLoadBus;

    protected final AggregatePersistBus aggregatePersistBus;

    protected final Serializer aggregateRootSerializer;

    protected HandlerRepository(HandlerRepository.Builder<T> builder) {
        super(builder);
        this.aggregateLoadBus = builder.aggregateLoadBus;
        this.aggregatePersistBus = builder.aggregatePersistBus;
        this.aggregateRootSerializer = builder.aggregateRootSerializer;
    }

    @Override
    protected JdbcAggregate<T> doCreateNew(Callable<T> factoryMethod) throws Exception {

        final JdbcAggregate<T> initialize = JdbcAggregate.initializeCreate(factoryMethod, aggregateModel(), eventStorageEngine, aggregateRootSerializer);
        return initialize;
    }


    @Override
    public List<JdbcAggregate<T>> doLoads(@Nonnull List<AggregateBizIdentifierVoucher> bizIdentifierVouchers, AggregateModel<T> aggregateModel, boolean enableCaching) {
        // 创建加载命令
        List<LoadMessage<Object, T>> loadMessages = new ArrayList<>(bizIdentifierVouchers.size());
        for (AggregateBizIdentifierVoucher bizIdentifierVoucher : bizIdentifierVouchers) {
            final GenericLoadMessage<Object, T> loadMessage = new GenericLoadMessage<>(bizIdentifierVoucher.getBizIdentifier(), bizIdentifierVoucher.getBizIdentifierName(), aggregateModel);
            loadMessage.setEnableCaching(enableCaching);
            loadMessages.add(loadMessage);
        }
        for (int i = 0; i < loadMessages.size(); i++) {
            if (i + 1 < loadMessages.size()) {
                loadMessages.get(i).next(loadMessages.get(i + 1));
            }
        }

        List<JdbcAggregate<T>> result = new ArrayList<>();
        // 异常查询
        for (final LoadMessage<Object, T> loadMessage : loadMessages) {
            try {
                final T aggregateRoot = aggregateLoadBus.load(loadMessage);
                if (aggregateRoot == null) {
                    result.add(null);
                } else {
                    final JdbcAggregate<T> jdbcAggregate = JdbcAggregate.initializeLoad(() -> aggregateRoot,
                            loadMessage.getAggregateModel(), eventStorageEngine, aggregateRootSerializer);
                    result.add(jdbcAggregate);
                }
            } catch (Exception e) {
                log.warn("加载异常",e);
                throw new AggregateNotFoundException(loadMessage.getIdentifier(), "加载异常" + loadMessage.getAggregateNaming(), e);
            }
        }
        return result;
    }

    @Override
    protected void doSaves(List<JdbcAggregate<T>> aggregates) {
        if (aggregates == null || aggregates.isEmpty()) {
            return;
        }
        List<GenericPersistMessage<T>> persistMessages = new ArrayList<>();
        for (final JdbcAggregate<T> aggregate : aggregates) {
            GenericPersistMessage<T> persistMessage = new GenericPersistMessage<>(aggregate, Map.of("aggregateRootSnapshot", aggregate.getSnapshotAggregateRoot()));
            persistMessages.add(persistMessage);
        }
        // 填写相同持久化对象
        generatePersistMessage(persistMessages);
        for (GenericPersistMessage<T> persistMessage : persistMessages) {
            try {
                aggregatePersistBus.save(persistMessage);
            } catch (Exception e) {
                log.error("持久化异常:", e);
                throw new RuntimeException(e);
            }
        }


    }

    private void generatePersistMessage(List<GenericPersistMessage<T>> persistMessages) {

        for (int i = 0; i < persistMessages.size() - 1; i++) {
            persistMessages.get(i).next(persistMessages.get(i + 1));
        }

    }


    public static <T> Builder<T> builder(AggregateModel<T> aggregateModel) {
        return new Builder<>(aggregateModel);
    }


    public static class Builder<T> extends AbstractRepository.Builder<T> {

        protected AggregateLoadBus aggregateLoadBus;

        protected AggregatePersistBus aggregatePersistBus;



        protected Serializer aggregateRootSerializer;

        protected Builder(AggregateModel<T> aggregateModel) {
            super(aggregateModel);
        }


        public Builder<T> aggregateLoadBus(@Nonnull AggregateLoadBus aggregateLoadBus) {
            assertNonNull(aggregateLoadBus, "AggregateLoadBus may not be null");
            this.aggregateLoadBus = aggregateLoadBus;
            return this;
        }

        public Builder<T> aggregatePersistBus(@Nonnull AggregatePersistBus aggregatePersistBus) {
            assertNonNull(aggregatePersistBus, "AggregatePersistBus may not be null");
            this.aggregatePersistBus = aggregatePersistBus;
            return this;
        }

        public Builder<T> aggregateRootSerializer(@Nonnull Serializer serializer) {
            assertNonNull(serializer, "serializer may not be null");
            this.aggregateRootSerializer = serializer;
            return this;
        }

        public HandlerRepository<T> build() {
            return new HandlerRepository<>(this);
        }
    }
}
